# -*- coding: utf-8 -*-
# @Time    : 2020/3/17 下午7:57
# @Author  : lilong


"""
1.创建类时先执行type的__init__方法,
2.当一个类实例化时(创建一个对象)执行type的__call__方法，__call__方法的返回值就是实例化的对象
　　　　__call__内部调用
　　　　　　-类.__new__方法，创建一个对象
　　　　　　-类.__init__方法，初始化对象
"""


# 自定义元类
# =========================================================
class CustomMetaclass(type):

    def __init__(cls, what, bases=None, dict=None):
        print("CustomMetaclass.__init__ cls:", cls)
        super().__init__(what, bases, dict)

    def __call__(cls, *args, **kwargs):
        print("CustomMetaclass.__call__ args:", args, kwargs)

        # 创建继承元类的对象，实际要实例化的类对象
        self = super(CustomMetaclass, cls).__call__(*args, **kwargs)
        print("CustomMetaclass.__call__ self:", self)
        return self


class CustomClass(metaclass=CustomMetaclass):

    # 创建一个对象，是和__init__被一起调用的
    def __new__(cls, *args, **kwargs):
        self = super().__new__(cls)
        print("CustomClass.__new__, self:", self)
        return self

    # 初始化一个对象
    def __init__(self, *args, **kwargs):
        print("CustomClass.__init__ self:", self)
        super().__init__()

    # 类中实现了 __call__ 方法，那么实例对象也将成为一个可调用对象
    def __call__(self, *args, **kwargs):
        print("CustomClass.__call__ args:", args)


obj = CustomClass("Meta arg1", "Meta arg2", kwarg1=1, kwarg2=2)
print(type(CustomClass))
print(obj)
obj("arg1", "arg2")
print("######################")


# 使用元类构建单例模式
class Singleton2(type):
    def __init__(cls, name, bases, attrs):
        super(Singleton2, cls).__init__(name, bases, attrs)
        cls._instance = None

    def __call__(cls, *args, **kwargs):
        """type的__call__方法里面会先执行__new__方法，再去执行__init__方法。
            所以，Foo就是用type创建出来的
        """
        if not cls._instance:
            cls._instance = super(Singleton2, cls).__call__(*args, **kwargs)
        # return super(Singleton2, cls).__call__(*args, **kwargs)  # 用于返回每一个新建的对象
        return cls._instance   # 用于返回唯一的对象


class MyClass(metaclass=Singleton2):
    def __init__(self, name):
        self.__name = name

    def getName(self):
        return self.__name


s0 = MyClass("Zhangsan")
s1 = MyClass("Lisi")
print(s0.getName(), s1.getName())
print("id(s0):", id(s0), "id(s1):", id(s1))
print("s0 == s1:", s0 == s1)

